﻿#include "remoteobject_p.h"
#include "metafunction.h"
#include "metasignal.h"
#include "metaproperty.h"
#include "remoteobjectnode.h"
#include "dynamicmetacreator.h"
#include "dynamicremoteobject.h"
#include "reflectutils.h"

BeginMetaData(DynamicRemoteObject)
META_DefaultConstructor


EndMetaData


int GetRemoteId(const std::vector<std::string> & s){
    const static char t[] = "REMOTE:";
    for(auto &i:s){
        if(i.find(t) != -1){
            return std::atoi(i.data() + sizeof(t) - 1);
        }
    }

    return -1;
}

DynamicRemoteObject::DynamicRemoteObject()
{
    m_metaInfo = staticMetaInfo();
}

DynamicRemoteObject::~DynamicRemoteObject()
{

}

void DynamicRemoteObject::SetRemoteProperty(const char *name, Variant value)
{
    auto property = GetMetaInfo().GetProperty(GetMetaInfo().IndexOfProperty(name));

    if(!property.isValid()){
        return;
    }

    int localIndex = property.Index();
    int RemoteIndex = ToRemoteProperty(localIndex);

    if(RemoteIndex < 0){
        return;
    }

    PushRemotePropertyImp(RemoteIndex,value);
}

Variant DynamicRemoteObject::GetRemoteProperty(const char *name)
{
	auto property = GetMetaInfo().GetProperty(GetMetaInfo().IndexOfProperty(name));

    if(!property.isValid()){
        return Variant();
    }

    int localIndex = property.Index();
    int RemoteIndex = ToRemoteProperty(localIndex);
    if(RemoteIndex < 0){
        return Variant();
    }
    return GetRemotePropertyImp(RemoteIndex);
}

GenericSignal *DynamicRemoteObject::GetRemoteSignal(const char *signature)
{
    auto signal = GetMetaInfo().GetSignal(GetMetaInfo().IndexOfSignal(signature));

    if(!signal.isValid()){
        return NULL;
    }

    int localIndex = signal.Index();
    int RemoteIndex = ToRemoteSignal(localIndex);
    if(RemoteIndex < 0){
        return NULL;
    }
    return GetRemoteSignalImp(RemoteIndex);
}

std::shared_ptr<WorkFuture<Variant>> DynamicRemoteObject::CallRemoteFunction(const char *signature, const std::vector<Variant> &param)
{
    if(GetStatus() != S_Normal){
        return std::shared_ptr<WorkFuture<Variant>>();
    }

    auto func = GetMetaInfo().GetFunction(GetMetaInfo().IndexOfFunction(signature));

    if(!func.isValid()){
        return std::shared_ptr<WorkFuture<Variant>>();
    }

    int localIdx = func.Index();

    int remoteIdx = ToRemoteFunction(localIdx);

    if(remoteIdx < 0){
        return std::shared_ptr<WorkFuture<Variant>>();
    }

    return CallRemoteFunctionImp(remoteIdx,param,true);
}

void DynamicRemoteObject::PostRemoteFunction(const char *name, const std::vector<Variant> &param)
{
    if(GetStatus() != S_Normal){
        return;
    }

    std::vector<MetaTypeId> types;
    for(const auto& i:param)
    {
        types.push_back(i.TypeId());
    }
    std::string sig = ReflectUtils::GetSignature(name,types);

	auto func = GetMetaInfo().GetFunction(GetMetaInfo().IndexOfFunction(sig.c_str()));

    if(!func.isValid()){
        return;
    }

    int localIdx = func.Index();

    int remoteIdx = ToRemoteFunction(localIdx);

    if(remoteIdx < 0){
        return;
    }

    CallRemoteFunctionImp(remoteIdx,param,false);
}

unsigned long long DynamicRemoteObject::DoGetTypeSignature()
{
	return GetSignature(GetMetaInfo());
}

MetaInfo DynamicRemoteObject::GetMetaInfo() const
{
    return m_metaInfo;
}

void DynamicRemoteObject::Redirect(const DynamicMetaInfoData &meta)
{
    Redirect(CreateDynamicMetaInfo(meta));
}

void DynamicRemoteObject::Redirect(const MetaInfo &meta)
{
    this->m_metaInfo = meta;
    MetaInit();
}

void DynamicRemoteObject::MetaInit()
{
    m_externalProperty.clear();
    m_externalSignals.clear();

    funMap.clear();
    propertyMap.clear();
    signalMap.clear();

    int functionCount = m_metaInfo.FunctionCount();
    for(int i = m_metaInfo.FunctionBeginIndex();i<functionCount;i++){
        auto fun = m_metaInfo.GetFunction(i);
        int remote = GetRemoteId(fun.GetFunctionInfos());

        funMap[i] = remote;
    }

	int signalCount = m_metaInfo.SignalCount();

	for (int i = m_metaInfo.SignalBeginIndex(); i < signalCount; i++) {
		MetaSignal signal = m_metaInfo.GetSignal(i);
		int remote = GetRemoteId(signal.GetSignalInfo());
		signalMap[i] = remote;
		m_externalSignals[remote] = std::shared_ptr<GenericSignal>(new GenericSignal(signal.GetParamTypes()));
	}

    int propertyCount = m_metaInfo.PropertyCount();
    for(int i = m_metaInfo.PropertyBeginIndex();i < propertyCount;i++){
        auto property = m_metaInfo.GetProperty(i);
        int remote = GetRemoteId(property.GetPropertyInfo());
        propertyMap[i] = remote;
		LocalProperty pro;
		int localNotifierIdx = property.GetNotifier().Index();;
		pro.notifer_remote = signalMap[localNotifierIdx];
		m_externalProperty[remote] = pro;
    }


}

std::shared_ptr<WorkFuture<Variant>> DynamicRemoteObject::CallRemoteFunctionImp(int RemoteIndex, const std::vector<Variant> &param, bool isSync)
{
    auto node = dynamic_cast<RemoteObjectNode*>(GetNode());

    return node->invokeFunction(this,RemoteIndex,param,isSync);
}

void DynamicRemoteObject::PushRemotePropertyImp(int RemoteIndex, Variant value)
{
    auto node = dynamic_cast<RemoteObjectNode*>(GetNode());

    return node->pushProperty(this,RemoteIndex,value);
}

Variant DynamicRemoteObject::GetRemotePropertyImp(int RemoteIndex) const
{
    return m_externalProperty.at(RemoteIndex).value;
}

void DynamicRemoteObject::UpdateValue(int RemoteIndex, Variant value)
{
    m_externalProperty[RemoteIndex].value = value;
	GetRemoteSignalImp(m_externalProperty[RemoteIndex].notifer_remote)->DynamicInvoke({ value });
}

void DynamicRemoteObject::ReceiveSignal(int RemoteIndex, const VariantList &param)
{
    m_externalSignals[RemoteIndex]->DynamicInvoke(param);
}

GenericSignal *DynamicRemoteObject::GetRemoteSignalImp(int RemoteIndex)
{
    return m_externalSignals[RemoteIndex].get();
}

int DynamicRemoteObject::ToRemoteProperty(int index)
{
    if(staticMetaInfo() == GetMetaInfo()){
        return -1;
    }

    return propertyMap.at(index);
}

int DynamicRemoteObject::ToRemoteFunction(int index)
{
    if(staticMetaInfo() == GetMetaInfo()){
        return -1;
    }

    return funMap.at(index);
}

int DynamicRemoteObject::ToRemoteSignal(int index)
{
	if (staticMetaInfo() == GetMetaInfo()) {
		return -1;
	}

	return signalMap.at(index);
}
